<?php
System::import('php/lang/Comparable.interface.php');
System::import('php/lang/Object.class.php');

System::import('php/util/Utility.class.php');

class String extends Object implements Comparable {
	private $_value;
	
	public function __construct($value = '') {
		if(Utility::existsVar($value))
			$this->_value = (string) $value;
		else
			$this->_value = '';
	}
	
	/**
	 * Copies this string replacing occurrences of the specified character with
	 * another character.
	 * 
	 * @param String oldChar
	 * o caracter a ser substituido.
	 * @param String newChar
	 * o caracter substituinte.
	 * @return String uma nova String com as ocorrências de oldChar substituído por newChar.
	 */
	public function replace($oldChar, $newChar) {
		if(self::type($oldChar) != self::$STRING && self::type($newChar) != self::$STRING)
			return $this;
		
		$index = $this->indexOf($oldChar, 0);
		
		if($index == -1)
			return $this;
		
		$this->_value = str_replace($oldChar, $newChar, $this->_value);
		
		return $this;
	}
	
	/**
	 * Searches in this string for the first index of the specified character.
	 * The search for the character starts at the beginning and moves towards
	 * the end of this string.
	 * 
	 * @param c
	 * the character to find.
	 * @return the index in this string of the specified character, -1 if the
	 * character isn't found.
	 */
	public function indexOf($c) {
		for($i = 0; $i < $this->lenght(); $i++) {
			if($this->_value[$i] == $c) {
				return $i;
			}
		}
		
		return -1;
	}
	
	/**
	 * Returns the character at the specified offset in this string.
	 * 
	 * @param index
	 * the zero-based index in this string.
	 * @return the character at the index.
	 * @throws IndexOutOfBoundsException
	 * if {@code index < 0} or {@code index >= length()}.
	 */
	public function charAt($index) {
		if(0 <= $index && $index < $this->lenght()) {
			return $this->_value[$index];
		}
	
		//throw new StringIndexOutOfBoundsException();
	}
	
	/**
	 * Concatenates this string and the specified string.
	 * 
	 * @param string
	 * the string to concatenate
	 * @return a new string which is the concatenation of this string and the
	 * specified string.
	 */
	public function concat($string) {
		$this->_value .= $this->valueOf($string);
		
		return $this->_value;
	}
	
	/**
	 * Compares the specified string to this string to determine if the
	 * specified string is a prefix.
	 * 
	 * @param prefix
	 * the string to look for.
	 * @return {@code true} if the specified string is a prefix of this string,
	 * {@code false} otherwise
	 * @throws NullPointerException
	 * if {@code prefix} is {@code null}.
	 */
	public function startsWith(String $prefix, $case = true) {
		if($case) {
			return (strcmp(substr($this->_value, 0, strlen($prefix)), $prefix) === 0);
		}
		
		return (strcasecmp(substr($this->_value, 0, strlen($prefix)), $prefix) === 0);
	}
	
	/**
	 * Compares the specified string to this string to determine if the
	 * specified string is a suffix.
	 * 
	 * @param suffix
	 * the suffix to look for.
	 * @return {@code true} if the specified string is a suffix of this string,
	 * {@code false} otherwise.
	 * @throws NullPointerException
	 * if {@code suffix} is {@code null}.
	 */
	public function endsWith(String $suffix, $case = true) {
		if($case) {
			return (strcmp(substr($this->_value, strlen($this->_value) - strlen($suffix)), $suffix) === 0);
		}
		
		return (strcasecmp(substr($this->_value, strlen($this->value) - strlen($suffix)), $suffix) === 0);
	}
	
	/**
	 * Retorna o índice dentro da String da última ocorrência do caractere especificado.
	 * 
	 * @param Integer $index
	 * 
	 * @return Character
	 */
	public function lastIndexOf($index) {
		return strrpos($this->_value, $index);
	}
	
	/**
	 * Answers if the size of this String is zero.
	 * 
	 * @return true if the size of this String is zero, false otherwise
	 */
	public function isEmpty() {
		return 0 == $this->lenght();
	}
	
	/**
	 * Copies a range of characters into a new string.
	 * 
	 * @param start
	 * the offset of the first character.
	 * @param end
	 * the offset one past the last character.
	 * @return a new string containing the characters from start to end - 1
	 * @throws IndexOutOfBoundsException
	 * if {@code start < 0}, {@code start > end} or {@code end >
	 * length()}.
	 */
	public function substring($start, $end = 0) {
		if($start == 0 && ($end == $this->lenght() || $end = 0))
			return substr($this->_value, $start, $this->lenght());
		
		if(0 <= $start && $start <= $end && $end <= $this->lenght())
			return substr($this->_value, $start, ($start + $end));
	}
	
	/**
	 * Retorna o tamanho da String
	 * 
	 * @return Integer
	 */
	public function lenght() {
		return strlen($this->_value);
	}
	
	/**
	 * Converte esta String em um novo Array de Character
	 * 
	 * @return array
	 */
	public function toCharArray() {
		return str_split($this->_value);
	}
	
	/**
	 * Converte a String para minúsculas
	 * 
	 * @return String
	 */
	public function toLowerCase() {
		return strtolower($this->_value);
	}
	
	/**
	 * Converte a String para maiúsculas
	 * 
	 * @return String
	 */
	public function toUpperCase() {
		return strtoupper($this->_value);
	}
	
	/**
	 * Retorna uma cópia da String, com espaços em branco à esquerda e à direita omitidos.
	 * 
	 * @return String
	 */
	public function trim() {
		return trim($this->_value);
	}
	
	/**
	 * Compara este objeto com a String especificada
	 * 
	 * @param String
	 * 
	 * @return Boolean
	 */
	public function equals($value) {
		return strcmp($this->_value, $value) == 0;
	}
	
	/**
	 * Compara este objeto com a String especificada, ignorando maiúsculo/minúsculo
	 * 
	 * @param String
	 * 
	 * @return Boolean
	 */
	public function equalsIgnoreCase($value) {
		return strcasecmp($this->_value, $value) == 0;
	}
	
	/**
	 * Compara duas String lexicograficamente
	 * 
	 * @param String
	 * 
	 * @return Integer
	 */
	public function compareTo($value) {
		$cmp = strcmp($this->_value, $value);
		
		if($cmp < 0)
			return -1;
		else if($cmp > 0)
			return 1;
		
		return $cmp;
	}
	
	/**
	 * Compara duas String lexicograficamente, ignorando maiúsculo/minúsculo
	 * 
	 * @param String
	 * 
	 * @return Integer
	 */
	public function compareToIgnoreCase($value) {
		$cmp = strcasecmp($this->_value, $value);
		
		if($cmp < 0)
			return -1;
		else if($cmp > 0)
			return 1;
		
		return $cmp;
	}
	
	/**
	 * Retorna a representação em String do objeto passado por parametro
	 * 
	 * @param Object $value
	 * 
	 * @return String
	 */
	public static function valueOf($value) {
		return new String($value);
	}
	
	/**
	 * Este objeto (que já é uma String) é por si só retornado
	 * 
	 * @return String
	 */
	public function __toString() {
		return $this->_value;
	}
}
?>